#include <iostream>
#include <thread>
#include "ConcurrentLinkedList.h"
using namespace std;

template<typename T>
void printList(const ConcurrentLinkedList<T>& list) {
    std::unique_ptr<Iterator<T>> iterator = list.getIterator();
    while (iterator->MoveNext()) {
        cout << iterator->current() << " ";
    }
    cout << endl;
}

template<typename T>
void printList2(ConcurrentLinkedList<T>& list) {
    while (!list.empty()) {
        std::optional<T> dat = list.poll_head();
        if (dat.has_value())
            cout << dat.value() << " ";
        else
            cout << "null ";
    }
    cout << endl;
}

ConcurrentLinkedList<int> list;

int main() {
    const int n = 6, m = 512;
    thread th[n * 2];
    for (int t = 0; t < n; t++) {
        th[t] = thread([] {
            for (int i = 0; i < m; i++) {
                list.push_head(i);
            }
        });
    }
    for (int t = n; t < n * 2; t++) {
        th[t] = thread([] {
            std::unique_ptr<RemovableIterator<int>> iterator = list.getRemovableIterator();
            while (iterator->MoveNext()) {
                int dat = iterator->current();
                if (dat % 3 == 0 || dat % 7 == 0) {
                    //if (list.remove(dat))
                    if (iterator->remove())
                        list.push_head(dat);
                } else if (dat % 11 == 0) {
                    std::optional<int> _dat = list.poll_head();
                    if (_dat.has_value()) {
                        list.push_head(_dat.value());
                    }
                }
            }
        });
    }
    for (auto& t : th) t.join();
    printList(list);

    {
        int count[m] = {0};
        std::unique_ptr<RemovableIterator<int>> iterator = list.getRemovableIterator();
        while (iterator->MoveNext()) {
            count[iterator->current()]++;
        }
        bool succ = true;
        for (int i = 0; i < m; i++) {
            if (count[i] != n) {
                int diff = count[i] - n;
                string sdiff;
                if (diff > 0) sdiff.append("+");
                sdiff.append(to_string(diff));
                cerr << "TEST FAILED!!! i: " << i << ", diff=" << sdiff << endl;
                succ = false;
            }
        }
        if (succ)
            cout << "TEST PASSED" << endl;
    }

    // printList2(list);

    return 0;
}